package com.example.demo

import com.open.demo.bean.NewData
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.*
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.quality.Strictness

/**
 * 文章地址:
 * https://github.com/mockito/mockito-kotlin/wiki/Mocking-and-verifying
 * https://johnnyshieh.me/posts/unit-test-mockito-2-in-kotlin/
 *
 */
// 除了显式地调用MockitoAnnotations.initMocks(this)外，还可以使用MockitoJUnitRunner或者MockitoRule
@RunWith(MockitoJUnitRunner::class)
// 或 @Rule @JvmField
//    val mockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS)
class MockUnitTest {

    @Rule @JvmField
    val mockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS)

    /**
     * Mockito 还提供了 @Mock 等注解来简化创建 mock 对象的工作
     */
    @Mock
    lateinit var data:NewData


    @Before
    fun setUp() {
        // 上面的变量需要使用，必须要调用这行代码初始化 Mock
//        MockitoAnnotations.initMocks(this)
    }

    /**
     * Mockito 很容易验证 mock 对象的方法调用，注意这里的限制是只能验证 mock 对象的方法调用
     */
    @Test
    fun mockCall() {
        val mockedList = mock(mutableListOf<String>().javaClass)
        // using mock object
        mockedList.add("one")
        mockedList.clear()
        // verification
        verify(mockedList).add("one")
        verify(mockedList).clear()

        // following two verifications work exactly the same - times(1) is used by default
        verify(mockedList).add("once");
        verify(mockedList, times(1)).add("once")
        // exact number of invocations verification
        verify(mockedList, times(2)).add("twice")
        verify(mockedList, times(3)).add("three times")
        // verification using never(). never() is an alias to times(0)
        verify(mockedList, never()).add("never happened")
        // verification using atLeast()/atMost()
        verify(mockedList, atLeastOnce()).add("three times")
        verify(mockedList, atLeast(2)).add("three times")
        verify(mockedList, atMost(5)).add("three times")

        // 验证参数值
        // 上面的验证方法调用时，对于参数的校验使用的默认 equals 方法，除此之外也可以使用 argument matchers：
        verify(mockedList).add(anyString())
        verify(mockedList).add(notNull())
        verify(mockedList).add(argThat{ argument -> argument.length > 5 })
    }

    /**
     * 创建 mock 对象是 Mockito 框架生效的基础，有两种方式 mock 和 spy。
     * mock 对象的属性和方法都是默认的，例如返回 null、默认原始数据类型值（0 对于 int/Integer）或者空的集合，
     * 简单来说只有类的空壳子。
     * 而 spy 对象的方法是真实的方法，不过会额外记录方法调用信息，所以也可以验证方法调用。
     */
    @Test
    fun mockSpy() {
        val spyList = spy(mutableListOf<String>())
        // spy object call *real* methods
        spyList.add("one")
    }

    @Test
    fun testmock() {
        val mock:NewData = mock(NewData::class.java)
    }

}